﻿using System;
using System.Collections.ObjectModel;
using System.Device.Location;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Threading;
using Microsoft.Phone.Shell;
using NExtra.Geo;
using Windows.Devices.Geolocation;

namespace SkiTracker.ViewModel
{
    public class TrackPositionViewModel : MapViewModel
    {
        private readonly Geolocator _geolocator;

        private readonly PositionHandler _positionHandler;

        private readonly DispatcherTimer _timer;

        public TrackPositionViewModel()
        {
            Coordinates = new ObservableCollection<GeoCoordinate>();

            //Pitch = 55;
            ZoomLevel = 15;

            if (App.IsEmulator) _positionHandler = new PositionHandler();
            
            
            _geolocator = new Geolocator
                {
                    ReportInterval = 1000,
                    DesiredAccuracy = PositionAccuracy.High
                };
            _geolocator.PositionChanged += GeolocatorOnPositionChanged;


            StartStopTimerCommand = new RelayCommand(StartStopTimer);

            _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.5) };
            _timer.Tick += (sender, args) =>
                {
                    RaisePropertyChanged(() => ElapsedTime);
                    UpdateLiveTile();
                };
        }

        private void GeolocatorOnPositionChanged(Geolocator sender, PositionChangedEventArgs args)
        {
            CurrentLocation = args.Position.Coordinate.ToGeoCoordinate();

            #region Stuff for Map 

            if (IsHeadingAutomatic)
            {
                if (App.IsEmulator)
                {
                    if (Coordinates.Any())
                        Heading = _positionHandler.CalculateBearing(new Position(Coordinates.Last()),
                                                                    new Position(CurrentLocation));
                }
                else
                {
                    Heading = CurrentLocation.Course;
                }
            }


            if (IsTimerEnabled)
            {
                if (Coordinates.Any())
                    DistanceInKm += CurrentLocation.GetDistanceTo(Coordinates.Last()) / 1000;
            }
            
            #endregion

            //Coordinates.Add(coordinate);   -> muss aber am UI-Thread passieren
            DispatcherHelper.CheckBeginInvokeOnUI(() => Coordinates.Add(CurrentLocation));
        }

        private void UpdateLiveTile()
        {
            var tile = ShellTile.ActiveTiles.First();

            ShellTileData shellTileData = new FlipTileData
            {
                BackContent = string.Format("{0:f0} km/h \r\n{1:f2} km\r\n{2:HH:mm:ss}", SpeedInKmH, DistanceInKm, ElapsedTime),
                WideBackContent = string.Format("Speed {0:f0} km/h \r\nDistanz {1:f2} km\r\nZeit {2:HH:mm:ss}", SpeedInKmH, DistanceInKm, ElapsedTime),
                Count = 0,
                BackTitle = "Ski-Tracker",
                Title = string.Format("Speed {0:f0} km/h", SpeedInKmH),
            };

            if (tile != null) tile.Update(shellTileData);
            
        }

        public ObservableCollection<GeoCoordinate> Coordinates { get; private set; }

        public Point Transform { get { return new Point(0.5, 0.65); } }

        private GeoCoordinate _currentLocation = new GeoCoordinate(47, 12);
        public GeoCoordinate CurrentLocation
        {
            get { return _currentLocation; }
            set
            {
                _currentLocation = value;

                MaxSpeedInKmH = SpeedInKmH;

                

                DispatcherHelper.CheckBeginInvokeOnUI(() =>
                    {
                        RaisePropertyChanged(() => CurrentLocation);
                        RaisePropertyChanged(() => SpeedInKmH);
                    });
            }
        }


        public double SpeedInKmH
        {
            get
            {
                return (CurrentLocation == null 
                        || double.IsNaN(CurrentLocation.Speed)
                        || CurrentLocation.Speed > 130.0) 
                    ? 0.0 
                    : CurrentLocation.Speed*3.6;
            }
        }

        private double _maxSpeedInKmH;
        public double MaxSpeedInKmH
        {
            get { return _maxSpeedInKmH; }
            private set
            {
                if (value <= _maxSpeedInKmH) return;

                _maxSpeedInKmH = value;
                DispatcherHelper.CheckBeginInvokeOnUI(() => RaisePropertyChanged(() => MaxSpeedInKmH));
            }
        }

        private double _distanceInKm;
        public double DistanceInKm
        {
            get { return _distanceInKm; }
            set
            {
                _distanceInKm = value;
                DispatcherHelper.CheckBeginInvokeOnUI(() => RaisePropertyChanged(() => DistanceInKm));
            }
        }



        private bool _isHeadingAutomatic;
        public bool IsHeadingAutomatic
        {
            get { return _isHeadingAutomatic; }
            set
            {
                _isHeadingAutomatic = value;
                RaisePropertyChanged(() => IsHeadingAutomatic);
            }
        }

        public DateTime ElapsedTime { get { return new DateTime(ElapsedTimeSpan.Ticks); } }
        private TimeSpan ElapsedTimeSpan
        {
            get
            {
                if (_startTime == DateTime.MinValue) return TimeSpan.FromTicks(0);
                return _delta + (DateTime.Now - _startTime);
            }
        }
        private TimeSpan _delta;
        private DateTime _startTime;


        private bool _isTimerEnabled;
        public bool IsTimerEnabled
        {
            get { return _isTimerEnabled; }
            set
            {
                _isTimerEnabled = value;
                RaisePropertyChanged(() => IsTimerEnabled);
            }
        }

        public ICommand StartStopTimerCommand { get; private set; }

        private void StartStopTimer()
        {
            if (IsTimerEnabled)
            {
                _timer.Stop();
                _delta = ElapsedTimeSpan;            
            }
            else
            {
                _startTime = DateTime.Now;
                _timer.Start();
            }

            IsTimerEnabled = !IsTimerEnabled;
        }

    }
}


/*
        <BackgroundExecution>
          <ExecutionType Name="LocationTracking"/>
        </BackgroundExecution>
*/